using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Globalization;
using System.Data;
using Microsoft.Practices.CompositeWeb;
using WCSFContrib.ECommerceCatalog.CatalogData;
using WCSFContrib.ECommerceCatalog.BusinessEntities;
using WCSFContrib.ECommerceCatalog.BusinessEntities.Enums;
using WCSFContrib.ECommerceCatalog.Product.Interfaces.Services;
using WCSFContrib.ECommerceCatalog.User.Interfaces.Services;

namespace WCSFContrib.ECommerceCatalog.User.Services
{
    public class OrdersService : IOrdersService
    {
        private CatalogDataSet _catalogDataSet;
        private IItemsService _itemsService;

        public OrdersService([ServiceDependency] IItemsService itemsService)
            : this(CatalogRepository.Instance, itemsService)
        { }

        public OrdersService(CatalogDataSet ds, IItemsService itemsService)
        {
            _catalogDataSet = ds;
            _itemsService = itemsService;
        }

        public ICollection<Order> AllOrders
        {
            get
            {
                ICollection<Order> orders = new List<Order>();
                foreach (CatalogDataSet.OrderRow row in _catalogDataSet.Order.Rows)
                {
                    orders.Add(TranslateFromOrderRowToOrderEntity(row));
                }
                return orders;
            }
        }

        public Order GetOrderById(int orderId)
        {
            CatalogDataSet.OrderRow orderRow = _catalogDataSet.Order.FindByOrderId(orderId);
            Order order;

            if (orderRow == null)
                return null;

            order = TranslateFromOrderRowToOrderEntity(orderRow);

            return order;
        }

        public ICollection<Order> GetOrdersByOrderStatus(OrderStatus orderStatus)
        {
            DataRow[] rows = _catalogDataSet.Order.Select(String.Format(CultureInfo.CurrentCulture, "OrderStatus='{0}'", (Int32)orderStatus));
            IList<Order> orders = new List<Order>(rows.Length);

            foreach (CatalogDataSet.OrderRow ordersRow in rows)
            {
                orders.Add(TranslateFromOrderRowToOrderEntity(ordersRow));
            }

            return orders;
        }

        public Collection<Order> GetOrdersByUserName(string userName)
        {
            string query = string.Format(CultureInfo.InvariantCulture, "UserName = '{0}'", userName);
            CatalogDataSet.OrderRow[] ordersRows = _catalogDataSet.Order.Select(query) as CatalogDataSet.OrderRow[];
            Collection<Order> orderList = new Collection<Order>();
            foreach (CatalogDataSet.OrderRow row in ordersRows)
            {
                Order order = TranslateFromOrderRowToOrderEntity(row);
                orderList.Add(order);
            }

            return orderList;
        }

        public void ChangeOrderStatus(int orderId, OrderStatus newOrderStatus)
        {
            CatalogDataSet.OrderRow orderRow = _catalogDataSet.Order.FindByOrderId(orderId);

            if (orderRow == null)
                return;

            orderRow.OrderStatus = (int)newOrderStatus;
        }

        public Order Checkout(string userName, ICollection<CartItem> cartItems, DateTime orderDate, Address billingAddress, Address shippingAddress, Payment paymentMethod)
        {
            _catalogDataSet.Order.AddOrderRow(userName, orderDate,
                                                billingAddress.AddressId,
                                                shippingAddress.AddressId,
                                                (int)OrderStatus.Open,
                                                paymentMethod.PaymentId);

            Collection<Order> orders = GetOrdersByUserName(userName);
            int orderId = orders[orders.Count - 1].OrderId;

            foreach (CartItem cartItem in cartItems)
            {
                AddOrderItem(orderId, cartItem.Item.ItemId, cartItem.Quantity);
            }

            Order order = GetOrderById(orderId);
            
            return order;
        }

        public void AddOrderItem(int cartId, int itemId, int quantity)
        {
            CatalogDataSet.OrderRow orderRow = _catalogDataSet.Order.FindByOrderId(cartId);
            CatalogDataSet.OrderItemRow orderItemRow;

            orderItemRow = _catalogDataSet.OrderItem.FindByOrderIdItem(orderRow.OrderId, itemId);

            CatalogDataSet.ItemRow itemRow = _catalogDataSet.Item.FindByItemId(itemId);
            _catalogDataSet.OrderItem.AddOrderItemRow(orderRow, itemRow, quantity);
        }

        private Address GetAddressById(int addressId)
        {
            CatalogDataSet.AddressRow addressRow = _catalogDataSet.Address.FindByAddressId(addressId);
            Address address = null;

            if (addressRow == null)
                return null;

            address = TranslateFromAddressRowToAddressEntity(addressRow);

            return address;
        }

        private Payment GetPaymentsById(int PaymentId)
        {
            CatalogDataSet.PaymentRow paymentRow = _catalogDataSet.Payment.FindByPaymentId(PaymentId);
            Payment payment = null;

            if (paymentRow == null)
                return null;

            payment = TranslateFromPaymentRowToPaymentEntity(paymentRow);

            return payment;
        }

        private Order TranslateFromOrderRowToOrderEntity(CatalogDataSet.OrderRow orderRow)
        {
            Order order = new Order();

            order.OrderId = orderRow.OrderId;
            order.User = orderRow.UserName;
            order.OrderDate = orderRow.OrderDate;
            order.BillingAddress = GetAddressById(orderRow.BillingAddress);
            order.ShippingAddress = GetAddressById(orderRow.ShippingAddress);
            order.OrderStatus = (BusinessEntities.Enums.OrderStatus)orderRow.OrderStatus;
            order.PaymentMethod = GetPaymentsById(orderRow.PaymentMethod);

            CatalogDataSet.OrderItemRow[] orderItemRows = orderRow.GetOrderItemRows();

            foreach (CatalogDataSet.OrderItemRow orderItemRow in orderItemRows)
            {
                OrderItem orderItem = TranslateFromOrderItemRowToOrderItemEntity(orderItemRow);
                order.OrderItems.Add(orderItem);
            }

            return order;
        }

        private static Address TranslateFromAddressRowToAddressEntity(CatalogDataSet.AddressRow addressRow)
        {
            Address address = new Address();

            address.Street = addressRow.Street;
            address.City = addressRow.City;
            address.State = addressRow.IsStateNull() ? null : addressRow.State;
            address.Country = address.Country;
            address.Phone = addressRow.IsPhoneNull() ? null : addressRow.Phone;

            return address;
        }

        private static Payment TranslateFromPaymentRowToPaymentEntity(CatalogDataSet.PaymentRow PaymentRow)
        {
            Payment payment = new Payment();

            payment.PaymentType = (BusinessEntities.Enums.PaymentType)PaymentRow.PaymentType;
            payment.PaymentInfo = PaymentRow.PaymentInfo;

            return payment;
        }

        private OrderItem TranslateFromOrderItemRowToOrderItemEntity(CatalogDataSet.OrderItemRow orderItemRow)
        {
            OrderItem orderItem = new OrderItem();

            orderItem.OrderId = orderItemRow.OrderId;
            orderItem.Item = _itemsService.GetItemById(orderItemRow.Item);
            orderItem.Quantity = orderItemRow.Quantity;

            return orderItem;
        }

        private CatalogDataSet.ItemRow TranslateFromItemEntityToItemRow(Item item)
        {
            CatalogDataSet.ItemRow itemRow = null;

            itemRow.ItemId = item.ItemId;
            itemRow.Name = item.Name;
            itemRow.Description = item.Description;
            itemRow.Image = item.Image;
            itemRow.Stock = item.Stock;
            itemRow.Price = item.Price;
            itemRow.Category = item.Category.CategoryId;

            return itemRow;
        }
    }
}
